/* vim: set sw=8 ts=8 sts=8 expandtab: */
#ifndef CMAID_MAP_GTEST
#define CMAID_MAP_GTEST

typedef Cmaid_Map *(*Cmaid_Gtest_Constructor_Pair)(const void *param1,
                                                    const void *param2);
#define CMAID_GTEST_CONSTRUCTOR_PAIR(cb) (Cmaid_Gtest_Constructor_Pair)(cb)

#if GTEST_HAS_COMBINE
class Cmaid_Map_Gtest
	: public ::testing::TestWithParam
          < ::std::tr1::tuple<
	  	Cmaid_Gtest_Constructor_Pair,
		Cmaid_Gtest_Constructor_Param, /* first parameter passed to
                                                         the constructor */
                Cmaid_Gtest_Data,              /* the key data */
		Cmaid_Gtest_Constructor_Param, /* second parameter passed to
                                                         the constructor */
                Cmaid_Gtest_Data               /* the value data */
             >
          >

{
        protected:

        Cmaid_Set *map;
        struct
        {
                Cmaid_Gtest_Data data;
                bool pointer_type;
        } key, value;
        size_t count;

        virtual void SetUp()
        {
                Cmaid_Gtest_Constructor_Param param1;
                Cmaid_Gtest_Constructor_Param param2;
                Cmaid_Gtest_Constructor_Pair constructor;

                constructor = ::std::tr1::get<0>(GetParam());
                param1 = ::std::tr1::get<1>(GetParam());
                key.data = ::std::tr1::get<2>(GetParam());
                param2 = ::std::tr1::get<3>(GetParam());
                value.data = ::std::tr1::get<4>(GetParam());

                key.pointer_type = param1.pointer_type;
                value.pointer_type = param2.pointer_type;
                /* create the list */
                map = constructor(param1.param, param2.param);
                count = std::min(key.data.count, value.data.count);
                ASSERT_TRUE(NULL != map);
        }
        virtual void TearDown()
        {
                if (map)
                        cmaid_container_destroy(map);
                map = NULL;
        }
        size_t dataCount()
        {
                return count;
        }
        bool keyIsPointerType()
        {
                return key.pointer_type;
        }
        void *keyAt(size_t i)
        {
                return key.data.data_get(key.data.data, i);
        }
        bool keyEquals(const void *data1, const void *data2)
        {
                return !key.data.compare(data1, data2);
        }
        int keyCompare(const void *data1, const void *data2)
        {
                return key.data.compare(data1, data2);
        }
        std::string keyToString(const void *d)
        {
                return key.data.to_string(d);
        }
        bool valueIsPointerType()
        {
                return value.pointer_type;
        }
        void *valueAt(size_t i)
        {
                return value.data.data_get(value.data.data, i);
        }
        bool valueEquals(const void *data1, const void *data2)
        {
                return !value.data.compare(data1, data2);
        }
        int valueCompare(const void *data1, const void *data2)
        {
                return value.data.compare(data1, data2);
        }
        std::string valueToString(const void *d)
        {
                return value.data.to_string(d);
        }
        virtual void fill()
        {
                for (int i = 0; i < dataCount(); i++)
                        cmaid_map_set(map, keyAt(i), valueAt(i));
        }
};

#define ASSERT_KEY_EQ(d1, d2) ASSERT_TRUE(keyEquals((d1), (d2))) << \
		keyToString((d1)) << " != " << keyToString((d2))

#define ASSERT_KEY_NE(d1, d2) ASSERT_FALSE(keyEquals(d1, d2)) << \
		keyToString(d1) << " == " << keyToString(d2)

#define ASSERT_KEY_ITER_IS(iter, index, data) \
	do { \
		void *__data = data; \
		\
		ASSERT_EQ(index, cmaid_iter_index_get(iter)); \
		if (__data) \
			ASSERT_KEY_EQ(__data, cmaid_iter_current(iter)); \
		else \
			ASSERT_TRUE(NULL == cmaid_iter_current(iter)); \
	} while (0)

#define ASSERT_VALUE_EQ(d1, d2) ASSERT_TRUE(valueEquals((d1), (d2))) << \
		valueToString((d1)) << " != " << valueToString((d2))

#define ASSERT_VALUE_NE(d1, d2) ASSERT_FALSE(valueEquals(d1, d2)) << \
		valueToString(d1) << " == " << valueToString(d2)

#define ASSERT_VALUE_ITER_IS(iter, index, data) \
	do { \
		void *__data = data; \
		\
		ASSERT_EQ(index, cmaid_iter_index_get(iter)); \
		if (__data) \
			ASSERT_VALUE_EQ(__data, cmaid_iter_current(iter)); \
		else \
			ASSERT_TRUE(NULL == cmaid_iter_current(iter)); \
	} while (0)

#endif /* GTEST_HAS_COMBINE */

#endif /* CMAID_MAP_GTEST */
